/*
 * Copyright (c) 2007, TopCoder, Inc. All rights reserved.
 */

using System;
using System.Drawing;
using System.Windows.Forms;

namespace TopCoder.WinForms.Controls.CalendarView.Views
{
    /// <summary>
    /// <para>Extension of <see cref="NavigationPanel"/>.
    /// It can respond to mouse-over events so it can display data as a popup.</para>
    /// <para>This is the base class for all panel enhancements in this component that render
    /// a popup when the mouse is over it. Basically this panel extension will render a popup,
    /// which is a <see cref="ToolStripDropDown"/> control.
    /// Concrete extensions will determine what is drawn when the popup is activated via the
    /// <see cref="PopupPanel.DrawPanel(Panel,ToolStripDropDown)"/> abstract method.</para>
    /// </summary>
    /// <remarks>Thread Safety: This class is immutable and thread safe.</remarks>
    /// <author>Ghostar</author>
    /// <author>yext</author>
    /// <author>argolite</author>
    /// <author>alex.dolin</author>
    /// <version>1.1</version>
    /// <copyright>Copyright (c) 2007, TopCoder, Inc. All rights reserved.</copyright>
    public abstract class PopupPanel : NavigationPanel
    {
        /// <summary>
        /// Represents the panel that will display the pop-up data.
        /// It will resemble the data seen in the views.
        /// Will not be null.
        /// </summary>
        private readonly Panel display;

        /// <summary>
        /// Represents the control that is the popup. It will contain the pop-up data.
        /// Will not be null.
        /// </summary>
        private readonly ToolStripDropDown popup;

        /// <summary>
        /// Represents the control that will directly host the display panel.
        /// Will not be null.
        /// </summary>
        private readonly ToolStripControlHost displayHost;

        /// <summary>
        /// Creates a new <see cref="PopupPanel"/> instance.
        /// Creates all the controls inside the panel.
        /// </summary>
        /// <param name="calendarView">The parent calendar view.</param>
        /// <param name="destinationViewName">The destination view's name
        /// for the calendar view control.</param>
        /// <param name="dateOfInterest">The date around which to wrap the destination view.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="calendarView"/> is null.</exception>
        public PopupPanel(AbstractCalendarView calendarView, string destinationViewName, DateTime dateOfInterest)
            : base(calendarView, destinationViewName, dateOfInterest)
        {
            display = new Panel();
            display.Paint += new PaintEventHandler(OnPopupPaint);

            displayHost = new ToolStripControlHost(display);
            displayHost.AutoSize = false;

            popup = new ToolStripDropDown();
            popup.AutoSize = false;
            popup.Items.Add(displayHost);
            popup.SizeChanged +=
                delegate
                    {
                        displayHost.Width = popup.Width;
                        displayHost.Height = popup.Height;
                    };
        }

        /// <summary>
        /// Called in response to mouse enter event.
        /// Simply calls <see cref="PopupPanel.DrawPanel"/>.
        /// </summary>
        /// <param name="e">The event arguments.</param>
        protected override void OnMouseEnter(EventArgs e)
        {
            base.OnMouseEnter(e);
            DrawPanel(display, popup);
        }

        /// <summary>
        /// Called in response to mouse leave event.
        /// Hides the popup dropdown.
        /// </summary>
        /// <param name="e">The event arguments.</param>
        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);
            popup.Hide();
        }

        /// <summary>
        /// Show popup in position where it doesn't overlap with the panel.
        /// </summary>
        /// <param name="width">Width of the popup.</param>
        /// <param name="height">Height of the popup.</param>
        protected void ShowPopup(int width, int height)
        {
            // popup will be displayed to the right of this panel
            // if there is enough space, otherwise it will be moved to fit on screen
            Point position = PointToScreen(new Point(Width, 0));

            if(position.Y < height)
            {
                // if cannot fit popup at the top of this panel, then show it at bottom
                position.Y += Height;
            }
            else
            {
                // show popup at the top of this panel
                position.Y -= height;
            }

            popup.Width = width;
            popup.Height = height;

            popup.Show(position);
        }

        /// <summary>
        /// <para>Displays the popup on the screen.</para>
        /// <para>Implementations must check whether the popup is required,
        /// determine size of the popup and then show it.</para>
        /// <para>Method <see cref="ShowPopup"/> should be used to display
        /// the popup in default position. Implementations should create and use
        /// <see cref="Graphics"/> of the <paramref name="display"/> panel to measure the size.</para>
        /// </summary>
        /// <param name="display">The panel that will hold all drawn data.</param>
        /// <param name="popup">The popup control that holds the panel data.</param>
        protected abstract void DrawPanel(Panel display, ToolStripDropDown popup);

        /// <summary>
        /// Draws the popup panel.
        /// </summary>
        /// <param name="sender">The sender of the event.</param>
        /// <param name="e">The event, containing the graphics.</param>
        protected abstract void OnPopupPaint(object sender, PaintEventArgs e);
    }
}